package com.csxh.web.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.Registration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.buf.UDecoder;
import org.apache.tomcat.util.http.Parameters;

public class WebUtil {

	public static final String INCLUDE_REQUEST = "includeRequest";
	public static final String FORWORD_REQUEST = "forwardRequest";

	// 与用户相关的key
	public static final String USER = "user";
	public static final String USER_LIST = "userList";
	public static final String USER_EMAIL = "userEmial";
	public static final String USER_PASSWORD = "password";
	public static final String USER_REMBER_ME = "remberMe";

	public static final String USER_LOGIN_SUCCESS = "success";
	public static final String USER_LOGIN_FAIL = "fail";

	public static final String QUERY_FIELD = "queryField";
	public static final String QUERY_PARAM = "queryParam";
	// 与操作有关的参数key
	public static final String OP = "op";
	public static final String OP_LIST = "list";
	public static final String OP_QUERY = "query";
	public static final String OP_ADD = "add";
	public static final String OP_DEL = "del";
	public static final String OP_UPDATE = "update";
	public static final String OP_FAIL = "fail";
	public static final String OP_OK = "ok";
	public static final String OP_SHOW = "show";

	public static final String FRAGMENT = "fragment";
	public static final String USERNAME = "username";
	public static final String PASSWORD = "password";
	public static final String CHARACTER_ENCODING = "encoding";
	public static final String WIDTH = "width";
	public static final String HEIGHT = "height";
	public static final String VERIFY_CODE = "verifyCode";
	public static final String BASE_PATH = "basePath";

	// 与分页有关的参数key
	public static final String PAGER = "pager";
	public static final String PAGER_SHOWJSP = "showJsp";
	public static final String PAGER_WHERECLASE = "whereClase";
	public static final String PAGER_WHEREPARAMS = "whereParams";
	public static final String PAGE_SIZE = "pageSize";
	public static final String PAGE_INDEX = "pageIndex";

	public static final Object PAGER_DATA_CLASS_NAME = "beanClassName";

	// 是否需要拦截处理的key
	private static final String FILTER_FLAG = "filter";
	private static final String FILTER_TRUE = "true";
	private static final String FILTER_BEFORE = "fitlerBefore";
	private static final String FILTER_AFTER = "fitlerAfter";

	public static final String BEAN_CLASS_NAME = "beanClassName";
	public static final String URL_BASE64 = "base64";
	public static final String INCLUDE_FIELDS = "includeFields";
	public static final String EXCLUDE_FIELDS = "excludeFields";
	public static final String QUERY_CONDITION_LIST = "queryConditionList";
	public static final String QUERY_EXPRESSION = "fieldQueryExpression";

	public static String getRealPath(HttpServletRequest request, String path) {
		return request.getServletContext().getRealPath(path);
	}

	public static String getRealContextPath(HttpServletRequest request) {
		return request.getServletContext().getRealPath("/");
	}

	public static String getRealWebInfPath(HttpServletRequest request) {
		return request.getServletContext().getRealPath("/WEB-INF/");
	}

	public static String getRealWebInfSubPath(HttpServletRequest request, String subPath) {
		subPath = StringUtil.trim(subPath, "[/\\]+");
		return request.getServletContext().getRealPath("/WEB-INF/" + subPath + "/");
	}

	public static String getRealWebInfLibPath(HttpServletRequest request) {

		return request.getServletContext().getRealPath("/WEB-INF/lib/");
	}

	public static String getRealWebInfLibSubPath(HttpServletRequest request, String subPath) {

		return request.getServletContext().getRealPath("/WEB-INF/lib/" + subPath);
	}

	public static InputStream getWebResourceAsStream(HttpServletRequest request, String resource) {
		resource = StringUtil.trim(resource, "[/\\]+");
		Set<String> pathSet = request.getServletContext().getResourcePaths("/" + resource);
		if (null == pathSet) {
			throw new RuntimeException("资源不存在");
		}
		for (String path : pathSet) {
			try {
				return new FileInputStream(path);
			} catch (FileNotFoundException e) {
				throw new RuntimeException("资源不存在");
			}
		}
		throw new RuntimeException("资源不存在");
	}

	public static String getWebResourceAsString(HttpServletRequest request, String resource, String encoding) {
		StringBuilder sb = new StringBuilder();

		InputStream in = getWebResourceAsStream(request, resource);
		try {
			BufferedReader bis = new BufferedReader(new InputStreamReader(in, encoding));
			String sline = null;
			while (null != (sline = bis.readLine())) {
				sb.append(sline);
			}
		} catch (Exception e) {

		}
		return sb.toString();
	}

	// 将数据保存到cookie中
	public static void saveDataToCookie(HttpServletResponse response, Map<String, Object> dataMap) {

		for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
			response.addCookie(new Cookie(entry.getKey(), entry.getValue().toString()));
		}

	}

	public static void saveLoginUser(HttpServletRequest request, Object u) {
		request.getSession().setAttribute(USER, u);
	}

	// 判断用户是否已经登录
	public static boolean checkLoginUser(HttpServletRequest req) {
		Object o = req.getSession().getAttribute(USER);
		return null != o;
	}

	// 获取登录对象
	@SuppressWarnings("unchecked")
	public static <T> T getLoginUser(HttpServletRequest req) {
		Object o = req.getSession().getAttribute(USER);
		return (T) o;
	}

	public static boolean isAjaxRequest(HttpServletRequest request) {
		String header = request.getHeader("X-Requested-With");
		boolean isAjax = "XMLHttpRequest".equals(header) ? true : false;
		return isAjax;
	}

	public static boolean isFilterRequest(HttpServletRequest request) {
		Object o = request.getAttribute(WebUtil.FILTER_BEFORE);
		return null != o;
	}

	public static boolean isIncludeRequest(HttpServletRequest request) {
		Object o = request.getAttribute(WebUtil.INCLUDE_REQUEST);
		return null != o;
	}

	public static boolean isForwardRequest(HttpServletRequest request) {
		Object o = request.getAttribute(WebUtil.FORWORD_REQUEST);
		return null != o;
	}

	// 根据请求路径在上下文对象中获取对应的派发对象
	public static RequestDispatcher findRequestDispatcher(ServletContext context, String servletPath) {
		// 通过上下文对象获取所有注册过的servlet
		@SuppressWarnings("unchecked")
		Map<String, Registration> map = (Map<String, Registration>) context.getServletRegistrations();
		for (Map.Entry<String, Registration> entry : map.entrySet()) {
			ServletRegistration reg = (ServletRegistration) entry.getValue();
			Collection<String> mappings = reg.getMappings();
			for (String mapping : mappings) {
				if (servletPath.equals(mapping)) {
					// 获取对应的servlet名称
					String servletName = entry.getKey();
					return context.getNamedDispatcher(servletName);
				}
			}
		}

		return null;

	}

	public static Map<String, String[]> parseRequestParamMap(String requestParams){
		
		Map<String, String[]> paramMap = new HashMap<String, String[]>();
		
		if (null==requestParams || "".equals(requestParams)) {
			return null;
		}
		String[] strs = requestParams.split("&");
		for (String str : strs) {
			// str形如：key=value
			String[] ss = str.trim().split("=");
			String key = ss[0].trim();
			String value = ss[1].trim();

			String[] values = paramMap.get(key);
			if (null==values) {
				values=new String[]{value};
			}else{
				values=Arrays.copyOf(values, values.length+1);
				values[values.length-1]=value;
			}
			paramMap.put(key, values);

		}
		return paramMap.size()>0 ? paramMap : null;
		
	}
	// 获取include请求参数
	public static Map<String, String[]> getIncludeRequestParamMap(ServletRequest request) {
		
		String param = (String) request.getAttribute("javax.servlet.include.query_string");
		return parseRequestParamMap(param);
		
	}

	public static String[] getIncludeRequestParamValues(ServletRequest request,String key) {
		Map<String, String[]> map=getIncludeRequestParamMap(request);
		return map.get(key);
	}

	public static String getIncludeRequestParamValue(ServletRequest request,String key) {
		Map<String, String[]> map=getIncludeRequestParamMap(request);
		return null==map.get(key) ? null : map.get(key)[0];
	}

	public static boolean hasIncludeRequestParamValue(ServletRequest request,String key) {
		Map<String, String[]> map=getIncludeRequestParamMap(request);
		return null==map.get(key) ? false : true;
	}

	// 将*.jsp请求转发给对应的*.sevlet处理
	public static void handleFilter(ServletRequest request, ServletResponse response, String urlPattern) {
		
		HttpServletRequest req = (HttpServletRequest) request;
		// 对于所有的ajax请求都不要进行拦截
		if (!isAjaxRequest(req)) {

			if(hasIncludeRequestParamValue(request, FILTER_FLAG)){
				
			}
			// 判断include请求是否需要被拦截处理
			boolean filterHandle = true;
			String path = (String) req.getAttribute("javax.servlet.include.servlet_path");
			if(null==path){
				path= req.getServletPath();
			}else{
				filterHandle=hasIncludeRequestParamValue(request, FILTER_FLAG);
			}
			
			if (filterHandle) {
				// 进行过滤处理
				String servletPath = path.replaceFirst("(\\.jsp)", urlPattern);

				try {

					RequestDispatcher requestDispatcher = findRequestDispatcher(request.getServletContext(),
							servletPath);
					// 判断是否有对应的servlet
					if (null != requestDispatcher) {

						// 设置一个标记：说明servlet请求是通过*.jsp拦截到达的
						request.setAttribute(FILTER_BEFORE, true);

						requestDispatcher.include(request, response);
						// 清除该标记
						request.removeAttribute(FILTER_BEFORE);
						request.setAttribute(FILTER_AFTER, true);

					}
				} catch (Exception e) {

				}
			}

		}

	}

	public static String strCookie(HttpServletRequest request, String key, String defaultValue) {

		Cookie[] cookies = request.getCookies();
		if (null == cookies) {
			return defaultValue;
		}
		for (Cookie cookie : cookies) {
			if (cookie.getName().equals(key)) {
				return cookie.getValue();
			}
		}

		return defaultValue;

	}

	public static Integer intCookie(HttpServletRequest request, String key, Integer defaultValue) {

		String value = strCookie(request, key, "");
		try {
			return Integer.parseInt(value);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			return defaultValue;
		}

	}

	public static Boolean booleanCookie(HttpServletRequest request, String key, Boolean defaultValue) {

		String value = strCookie(request, key, "");
		try {
			return Boolean.parseBoolean(value);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			return defaultValue;
		}

	}

	public static String strParam(HttpServletRequest request, String key, String defaultValue) {

		String value = request.getParameter(key);
		if (null == value) {
			value = defaultValue;
		}

		return value;

	}

	public static Integer intParam(HttpServletRequest request, String key, Integer defaultValue) {
		Integer value = defaultValue;

		String s = request.getParameter(key);
		if (null == s) {
			return defaultValue;
		}

		try {
			value = Integer.parseInt(s);
		} catch (NumberFormatException e) {
			value = defaultValue;
		}

		return value;

	}

	public static Boolean boolParam(HttpServletRequest request, String key, Boolean defaultValue) {

		Boolean value = defaultValue;

		String s = request.getParameter(key);
		if (null == s) {
			return defaultValue;
		}

		try {
			value = Boolean.parseBoolean(s);
		} catch (NumberFormatException e) {
			value = defaultValue;
		}

		return value;

	}

	// 从request中获取指定类型的参数值
	@SuppressWarnings("unchecked")
	public static <T> T param(String key, Class<T> clazz, HttpServletRequest request) {
		T ret = null;
		String s = request.getParameter(key);

		if (null == s) {
			return null;
		}

		if (clazz == String.class) {
			ret = (T) s;
		} else if (clazz == Integer.class) {
			Integer i = Integer.parseInt(s);
			ret = (T) i;
		} else if (clazz == Boolean.class) {
			Boolean b = Boolean.parseBoolean(s);
			ret = (T) b;
		} else if (clazz == Float.class) {
			Float f = Float.parseFloat(s);
			ret = (T) f;
		} else if (clazz == Double.class) {
			Double d = Double.parseDouble(s);
			ret = (T) d;
		} else {
			throw new RuntimeException("无效参数值");
		}

		return ret;
	}

	/**
	 * 
	 * @param context
	 *            上下文本对象，它是可以在多个方法之间共享数据的全局对象
	 * @param filename
	 * @param tag
	 *            EL表达式中的变量名称 ${tag} 返回新的文件路径
	 */
	public static String replaceFile(ServletContext context, String filename, String tagName) {

		Object o = context.getAttribute(tagName);
		// 如果存在对应的值，就转成字符串，否则为空串
		String tagValue = null != o ? o.toString() : "";

		String path = context.getRealPath(filename);
		String newPath = context.getRealPath("x" + filename);

		try {
			// 读取文件的内容filename
			FileReader fr = new FileReader(path);
			BufferedReader br = new BufferedReader(fr);
			StringBuffer sb = new StringBuffer();
			String lines;
			while ((lines = br.readLine()) != null) {
				sb.append(lines);
			}
			br.close();
			// 将${tagName}用tagValue来替换
			String str = sb.toString().replaceAll("\\$\\{" + tagName + "\\}", tagValue);
			// 再将内容写回到文件filename
			FileWriter fw = new FileWriter(newPath);
			fw.write(str);
			fw.close();
			Thread.sleep(300);
		} catch (Exception e) {
			// TODO: handle exception
		}

		return "x" + filename;

	}

	// 保存验证码
	public static void saveVerifyCode(HttpServletRequest request, String verifyCode) {

		request.getSession().setAttribute(VERIFY_CODE, verifyCode);

	}

	// 检测验证码
	public static boolean checkVerifyCode(HttpServletRequest request, String verifyCode) {

		Object o = request.getSession().getAttribute(VERIFY_CODE);

		return null != o && o.toString().equalsIgnoreCase(verifyCode);
	}

	public static void noCache(HttpServletResponse response) {

		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);

	}

	public static void useImageContentType(HttpServletResponse response) {
		response.setContentType("image/jpeg");
		// TODO Auto-generated method stub

	}

	public static void useJsonContentType(HttpServletResponse response) {
		response.setContentType("application/json");
		// TODO Auto-generated method stub

	}

	// 获取请求的来源URL
	public static String getFromUrl(HttpServletRequest request) {
		// TODO Auto-generated method stub
		return request.getHeader("Referer");
	}

	// 设置jsp的基路径，用于设置jsp页的base标签
	public static void buildBasePath(HttpServletRequest request) {
		// 构建请求的基路径
		StringBuffer sb = new StringBuffer();
		sb.append(request.getScheme()).append("://").append(request.getServerName()).append(":")
				.append(request.getServerPort()).append(request.getContextPath()).append("/");

		// 将基路径保存到请求上下文对象中，用于在jsp页中设置basepath
		request.setAttribute(BASE_PATH, sb.toString());

	}

	// 判断请求的op参数的值中是否是指定的内容
	public static boolean isOP(String op, HttpServletRequest request) {

		String s = request.getParameter(OP);

		return null != s && s.equals(op);
	}

	// 将一个输入串以base64格式进行编码
	public static String base64Foramt(String input) {

		if (StringUtil.isEmpty(input)) {
			return "";
		}

		return Base64.getUrlEncoder().encodeToString(input.getBytes());
	}

	// 将一个输入对象数组以base64格式进行编码
	public static String base64Foramt(Object[] inputs) {

		if (null == inputs || inputs.length == 0) {
			return "";
		}

		// 对数组进行序列化操作
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			ObjectOutputStream os = new ObjectOutputStream(out);
			for (Object input : inputs) {
				os.writeObject(input);
			}
			os.writeObject(null);// 结束标记
			os.flush();
			os.close();

			// 将比特数组转成字符串
			return Base64.getUrlEncoder().encodeToString(out.toByteArray());

		} catch (IOException e) {

		}

		return "";

	}

	// 将一个输入base64格式串以进行解码正常对象数组
	public static Object[] base64ParseToArray(String base64) {

		// TODO Auto-generated method stub
		if (null == base64 || "".equals(base64)) {
			return new Object[0];
		}
		// 将请求参数解码
		byte[] bs = Base64.getUrlDecoder().decode(base64);
		// 对参数进行反序列化操作
		// 构建比特输入流
		ByteArrayInputStream in = new ByteArrayInputStream(bs);
		// 构建对象输入流
		List<Object> list = new ArrayList<Object>();
		try {
			ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(in));
			Object obj = null;
			// 读取每一个对象
			while (null != (obj = ois.readObject())) {
				list.add(obj);
			}
			ois.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return list.toArray();

	}

	// 将一个输入base64格式串以进行解码正常字符串
	public static String base64ParseToString(String base64) {
		if (StringUtil.isEmpty(base64)) {
			return "";
		}

		return new String(Base64.getUrlDecoder().decode(base64));
	}

	public static String base64StringParam(HttpServletRequest request, String key, String defaultValue) {

		String value = WebUtil.strParam(request, key, defaultValue);
		return base64ParseToString(value);
	}

	public static Object[] base64ArrayParam(HttpServletRequest request, String key, Object[] defaultValues) {
		String value = WebUtil.strParam(request, key, "");
		return base64ParseToArray(value);
	}

}
